﻿using System;
using System.Text;

using System.Web;
using System.Security.Cryptography;

namespace AMT.IdentityModel.OAuth
{
	public class TokenFactory
	{
		#region Private constants
		private const string WRAP_Issuer_Label = "Issuer";
		private const string HMACSha256_Label = "HMACSHA256";
		#endregion

		#region Public static methods
		public static string CreateToken(string issuer, byte[] signingKey)
		{
			if (string.IsNullOrEmpty(issuer)) throw new ArgumentException("issuer");
			if (null == signingKey || 0 == signingKey.Length) throw new ArgumentException("signingKey");

			StringBuilder b = new StringBuilder(512);
			b.AppendFormat("{0}={1}", WRAP_Issuer_Label, HttpUtility.UrlEncode(issuer));
			// TODO: REVIEW: 8/31/2010, AppFabricLabs ignores ExpiresOn for incoming token requests.  Is that part of spec?
			//b.AppendFormat("&ExpiresOn={1}", null, DateTime.Now.AddDays(-7.0).ToFileTimeUtc());
			b.AppendFormat("&{0}={1}", HMACSha256_Label, GetSignature(b.ToString(), signingKey));

			return b.ToString();
		}

		public static string CreateToken(string issuer, string signingKeyBase64)
		{
			if (string.IsNullOrEmpty(issuer)) throw new ArgumentException("issuer");
			if (string.IsNullOrEmpty(signingKeyBase64)) throw new ArgumentException("signingKey");

			return CreateToken(issuer, Convert.FromBase64String(signingKeyBase64));
		}
		#endregion

		#region Private static methods
		private static string GetSignature(string unsignedToken, byte[] signingKey)
		{
			if (string.IsNullOrEmpty(unsignedToken)) throw new ArgumentException("unsignedToken");
			if (null == signingKey || 0 == signingKey.Length) throw new ArgumentException("signingKey");

			string signature = string.Empty;
			using (HMACSHA256 hmac = new HMACSHA256(signingKey))
			{
				// REVIEW: shouldn't this use UTF8 or other dynamically specified encoding?
				byte[] locallyGeneratedSignatureInBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(unsignedToken));
				signature = HttpUtility.UrlEncode(Convert.ToBase64String(locallyGeneratedSignatureInBytes));
			}
			return signature;
		}
		#endregion
	}
	// TokenFactory adapted from http://blogs.msdn.com/b/rockyh/archive/2010/04/15/azure-access-control-service-client-patterns-part-1.aspx
}
